/*
 * ==========================================================================*\
 * | $Id$
 * |*-------------------------------------------------------------------------*|
 * | Copyright (C) 2009 Virginia Tech | | This file is part of CloudSpace. | |
 * CloudSpace is free software; you can redistribute it and/or modify | it under
 * the terms of the GNU General Public License as published | by the Free
 * Software Foundation; either version 3 of the License, or | (at your option)
 * any later version. | | CloudSpace is distributed in the hope that it will be
 * useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of |
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General
 * Public License for more details. | | You should have received a copy of the
 * GNU General Public License | along with CloudSpace; if not, see
 * <http://www.gnu.org/licenses/>.
 * \*==========================================================================
 */

package cloudspace.security;

import java.util.ArrayList;

import javax.naming.NamingException;

import org.apache.log4j.Logger;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import edu.vt.middleware.ldap.Authenticator;
import edu.vt.middleware.ldap.AuthenticatorConfig;


// -------------------------------------------------------------------------
/**
 * Implements the LDAP authentication mechanism.
 * 
 * @author Tony Allevato
 * @author Last changed by $Author$
 * @version $Revision$, $Date$
 */
public class LDAPAuthenticationProvider implements AuthenticationProvider
{
    // ~ Methods ...............................................................

    // ----------------------------------------------------------
    public Authentication authenticate( Authentication authentication )
        throws AuthenticationException
    {
        String username = (String)authentication.getPrincipal();
        String password = (String)authentication.getCredentials();

        CloudSpaceUser user = UserRegistry.getInstance().getUser( username );

        if ( user == null || !"ldap".equals( user.getAuthenticator() ) )
        {
            throw new UsernameNotFoundException( "User '" + username
                + "' was not found" );
        }
        if ( !user.isEnabled() )
        {
            throw new DisabledException( "User " + username + " is disabled" );
        }
        try
        {
            // TODO move this configuration to the config file
            AuthenticatorConfig config = new AuthenticatorConfig( "ldap://authn.directory.vt.edu",
                "ou=People,dc=vt,dc=edu" );
            config.setTls( true );
            config.setUserField( new String[] { "uupid" } );

            Authenticator auth = new Authenticator( config );

            if ( auth.authenticate( username.toLowerCase(), password ) )
            {
                user = UserRegistry.getInstance().userByAddingPassword( user,
                    password );

                UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken( user,
                    authentication.getCredentials(),
                    new ArrayList<GrantedAuthority>() );

                result.setDetails( authentication.getDetails() );

                return result;
            }
            else
            {
                throw new BadCredentialsException( "Could not authenticate via LDAP" );
            }
        }
        catch ( NamingException e )
        {
            log.error( "Error occured during authentication on LDAP", e );
        }

        return null;
    }


    // ----------------------------------------------------------
    public boolean supports( Class<? extends Object> authentication )
    {
        return true;
    }

    // ~ Static/instance variables .............................................

    private static Logger log = Logger.getLogger( LDAPAuthenticationProvider.class );
}
